<?php
/**
 * User model class file.
 *
 * @package   models
 * @since     1.0
 * @filesource
 */

/**
 * This is the model class for table "{{user}}".
 * This is a DAO class which is used by DisorderController or other controllers
 * to operate data in database or return data in a specified format.
 *
 * The followings are the available columns in table '{{user}}':
 * @property integer $id
 * @property string $username
 * @property string $password
 * @property string $qualifications
 * @property string $evestgRef
 * @property string $title
 * @property string $firstName
 * @property string $lastName
 * @property string $address1
 * @property string $address2
 * @property string $suburb
 * @property string $state
 * @property string $postcode
 * @property string $country
 * @property string $phone
 * @property string $mobile
 * @property string $email
 * @property integer $globalCreate
 * @property integer $globalView
 * @property integer $globalDownload
 * @property integer $globalUpdate
 * @property integer $globalDelete
 * @property string $createTime
 *
 * The followings are the available model relations:
 * @property OrganizationAccess[] $organizationAccesses - an array of OrganizationAccess objects related to the user.
 * @property PatientSignal[] $patientSignals - an array of PatientSignal objects related to the user.
 */
class User extends CActiveRecord
{
	
	/**
	 * store User object of current login user
	 * is used by method self::getCurrentUser()
	 * @var User object
	 */
	private static $_currentUser;
	
	/**
	 * Returns the static model of the specified AR class.
	 * @return User the static model class
	 */
	public static function model($className=__CLASS__)
	{
		return parent::model($className);
	}
	
	/**
	 * Get the active record User object for current login user
	 * @return User the active record object for current login user.
	 */
	public static function getCurrentUser(){
		if(self::$_currentUser==null){
			self::$_currentUser=self::model()->findByPk(Yii::app()->user->id);
		}
		return self::$_currentUser;
	}

	/**
	 * Returns the table name related to this model class.
	 * @return string the associated database table name
	 */
	public function tableName()
	{
		return '{{user}}';
	}

	/**
	 * Returns the validation rules.
	 * The rules will be used when requesting validation by call self.validate().
	 * Many class method will call self.validate(), eg: CActiveRecord.save().
	 * @return array validation rules for model attributes.
	 */
	public function rules()
	{
		return array(
			//Make sure username is unique when creat or edit a record of user.
			array('username, password, globalCreate, globalView, globalDownload, globalUpdate, globalDelete', 'required'),
			array('qualifications, evestgRef', 'default','value'=>''),
			// username should be unique
			array('username', 'unique','on'=>'insert'),
			// email should be valid email format
			array('email','email','on'=>'insert,update'),
			array('globalCreate, globalView, globalDownload, globalUpdate, globalDelete', 'numerical', 'integerOnly'=>true),
			// The user cannot have global update access without create access
			array('globalUpdate', 'validateUpdateWithoutCreate'),
			array('username, password, evestgRef, title, firstName, lastName, address1, address2, suburb, state, postcode, country, phone, mobile, email', 'length', 'max'=>255),
			// username must be digits, numbers and underscores
			array('username', 'match', 'pattern'=>'/^[0-9a-zA-z_]+$/','message'=>'{attribute} is invalid. Must be letters, digits and underscore only.'),
			// The following rule is used by search().
			array('username, title, firstName, lastName,globalCreate, globalView, globalDownload, globalUpdate, globalDelete', 'safe', 'on'=>'search'),
		);
	}

	/** 
	 * Returns behaviors array
	 * @return array.
	 * @see CModel::behaviors()
	 */
	public function behaviors(){
		return array(
			// This setting will populate createTime variable automatically when 
			// creating an organization.
	  		'CTimestampBehavior' => array(
	  			'class' => 'zii.behaviors.CTimestampBehavior',
	  			'createAttribute' => 'createTime',
				'updateAttribute' => null,
			)
		);
	}

	/**
	 * Returns the relationship between this Model class and other Model class
	 * based on foreign key constraint between corresponding tables.
	 * The relationships involved in this application involves HAS_MANY, HAS_ONE, BELONGS_TO,
	 * please refer to Yii document for details.
	 * @return array relational rules.
	 */
	public function relations()
	{
		return array(
			// one user could have many organization accesses.
			'organizationAccesses' => array(self::HAS_MANY, 'OrganizationAccess', 'userId'),
			// statistics count for the numder of organization Accesses the user has.
			'organizationAccessesCount' => array(self::STAT, 'OrganizationAccess', 'userId'),
			// one user could upload many patient signals.
			'patientSignals' => array(self::HAS_MANY, 'PatientSignal', 'userId'),
			// statistics count for the number of organizations that the user has any access
			'organizationWithAccessCount'=>array(self::STAT, 'OrganizationAccess', 'userId',
				'condition'=>'(accessView=1 OR accessCreate=1 OR accessUpdate=1 '
							.'OR accessDelete=1 OR accessDownload=1)',
				'join'=>'INNER JOIN {{organization}} ON {{organization}}.id=organizationId AND {{organization}}.active=1'),
			// quick shortcut to get the assigned organization that is able to be viewed by user.
			'organizationWithAccessView'=>array(self::HAS_MANY, 'Organization', 'organizationId',
				'alias'=>'organization',
				'through'=>'organizationAccesses',
				'select'=>'id,name',
				'condition'=>'accessView=1 AND organization.active=1'),
			// quick shortcut to get the assigned organization that is able to be upload signal by user.
			'organizationWithAccessCreate'=>array(self::HAS_MANY, 'Organization', 'organizationId',
				'alias'=>'organization',
				'through'=>'organizationAccesses',
				'select'=>'id,name',
				'condition'=>'accessCreate=1 AND organization.active=1'),
		);
	}

	/**
	 * Returns the labels for each column variables. 
	 * This will be used to render label on page.
	 * @return array customized attribute labels (name=>label)
	 */
	public function attributeLabels()
	{
		return array(
			'id' => 'ID',
			'username' => 'Username',
			'password' => 'Password',
			'qualifications' => 'Qualifications',
			'evestgRef' => 'EVestG Accreditation Reference',
			'title' => 'Title',
			'firstName' => 'First Name',
			'lastName' => 'Last Name',
			'address1' => 'Address1',
			'address2' => 'Address2',
			'suburb' => 'Suburb',
			'state' => 'State',
			'postcode' => 'Postcode',
			'country' => 'Country',
			'phone' => 'Phone',
			'mobile' => 'Mobile',
			'email' => 'Email',
			'globalCreate' => 'Global Create',
			'globalView' => 'Global View',
			'globalDownload' => 'Global Download',
			'globalUpdate' => 'Global Update',
			'globalDelete' => 'Global Delete',
			'createTime' => 'Create Time',
		);
	}

	/**
	 * Retrieves a list of models based on the current search/filter conditions.
	 * @return CActiveDataProvider the data provider that can return the models based on the search/filter conditions.
	 */
	public function search($organizationId=null)
	{
		$criteria=new CDbCriteria;

		$criteria->compare('username',$this->username,true);
		$criteria->compare('title',$this->title,true);
		$criteria->compare('firstName',$this->firstName,true);
		$criteria->compare('lastName',$this->lastName,true);
		$criteria->compare('globalCreate',$this->globalCreate);
		$criteria->compare('globalView',$this->globalView);
		$criteria->compare('globalDownload',$this->globalDownload);
		$criteria->compare('globalUpdate',$this->globalUpdate);
		$criteria->compare('globalDelete',$this->globalDelete);
		
		if ($organizationId) {
			//if organizationId is specified, then more condition should be added.
			$criteria->join='INNER JOIN `neur_organization_access` 
							 ON `neur_organization_access`.`userId`=`t`.`id`';
			$criteria->compare('`neur_organization_access`.`organizationId`', $organizationId);
			$criteria->distinct=true;
		}

		return new CActiveDataProvider(get_class($this), array(
			'criteria'=>$criteria,
		));
	}
	

	/**
	 * Get the full name of a user.
	 * @return string
	 */
	public function getFullName() {
		return $this->firstName.' '.$this->lastName;
	}
	
	/**
	 * Get an array of Organization objects with which current user has view access.
	 * @return array()
	 */
	public function getViewableOrganizations() {
		if (Yii::app()->authManager->checkAccess('admin', $this->id)){
			//if current logined user is admin, then return a list of all active organization.
			return Organization::model()->findAll(array('select'=>'id,name'));
		}
		$organizations=array();
		if ($this->globalView) {
			// if user has global view access, the organizations that do not allow user create patient signals should be eliminated from the result list.
			$organizations=Organization::model()->findAll(
			array(
				'select'=>'id,name',
				'condition'=>'id NOT IN
					(SELECT a.organizationId FROM neur_organization_access a
					WHERE a.userId=:userId and a.accessView=0) AND active=1',
				'params'=>array(':userId'=>$this->id)
			));
		}
		else {
			$organizations=$this->organizationWithAccessView;
		}
		return $organizations;
	}

	/**
	 * Get an array of Organizations with which current user has create access.
	 * @return array()
	 */
	public function getCreatableOrganizations() {
		if (Yii::app()->authManager->checkAccess('admin', $this->id)){
			//if current logined user is admin, then return a list of all organization.
			return Organization::model()->findAll(array('select'=>'id,name'));
		}
		$organizations=array();
		if ($this->globalCreate) {
			// if user has global create access, the organizations that not allow the user to create patient signals should be eliminated from the result list.
			$organizations=Organization::model()->findAll(
			array(
				'select'=>'id,name',
				'condition'=>'id NOT IN
				(SELECT a.organizationId FROM neur_organization_access a
				WHERE a.userId=:userId and a.accessCreate=0) AND active=1',
				'params'=>array(':userId'=>$this->id),
			));
		}
		else {
			$organizations=$this->organizationWithAccessCreate;
		}
		return $organizations;
	}
	
	/**
	 * Validation function which is declared in $this->rules();
	 * Validate if the "update" access is granted without "create".
	 * @param string $attribute
	 * @param mixed $params
	 */
	public function validateUpdateWithoutCreate($attribute, $params) {
		if ($this->globalUpdate && !$this->globalCreate)
		$this->addError('globalUpdate', 'The user should be granted with "create" access if "update" is granted!');		
	}
}